package cn.com.cifi.mars.service.impl;

import cn.com.cifi.mars.bean.vo.report.InvestmentReturnReportVo;
import cn.com.cifi.mars.bean.vo.report.VsReturnReportVo;
import cn.com.cifi.mars.common.exception.MsgException;
import cn.com.cifi.mars.constant.*;
import cn.com.cifi.mars.entity.*;
import cn.com.cifi.mars.entity.common.IdmUser;
import cn.com.cifi.mars.entity.common.SysProjectFetchNumber;
import cn.com.cifi.mars.mapper.mars.*;
import cn.com.cifi.mars.mapper.wrapper.ReturnPlanVersionDetailWrapper;
import cn.com.cifi.mars.mapper.wrapper.ReturnPlanVersionWrapper;
import cn.com.cifi.mars.service.*;
import cn.com.cifi.mars.util.MyMapUtils;
import cn.com.cifi.mars.util.SysLogUtils;
import cn.com.cifi.mars.util.UUIDUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.sql.DataSource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 投资回款分析表 服务实现类
 * </p>
 *
 * @author JingYuanXiang
 * @since 2020-12-23
 */
@Slf4j
@Service
public class DmInvestmentReturnServiceImpl extends ServiceImpl<DmInvestmentReturnMapper, DmInvestmentReturn> implements DmInvestmentReturnService {

    @Autowired
    private DmInvestmentReturnMapper dmInvestmentReturnMapper;
    @Autowired
    private ReturnPlanVersionService returnPlanVersionService;
    @Autowired
    private ReturnPlanVersionCoefficientService returnPlanVersionCoefficientService;
    @Autowired
    private ReturnPlanVersionDetailService returnPlanVersionDetailService;
    @Autowired
    private ReturnPlanVersionDetailWrapper returnPlanVersionDetailWrapper;
    @Autowired
    private ReturnPlanVersionMapper returnPlanVersionMapper;
    @Autowired
    private SignPlanVersionMapper signPlanVersionMapper;
    @Autowired
    private ReturnPlanVersionWrapper returnPlanVersionWrapper;
    @Autowired
    private ReturnPlanVersionCoefficientMapper returnPlanVersionCoefficientMapper;
    @Autowired
    private ReturnPlanVersionDetailMapper returnPlanVersionDetailMapper;
    @Autowired
    private MymRoomsService mymRoomsService;
    @Autowired
    private SysProjectFetchNumberService sysProjectFetchNumberService;
    @Autowired
    DataSource dataSource;

    /**
     * 刷新投资回款分析表数据
     * @param projectId 项目id
     * @param yearMonth 年月
     */
    @Transactional
    @Override
    public void refreshDmInvestmentReturn(String projectId, String yearMonth) {
        if (StringUtils.isEmpty(yearMonth)) {
            throw new MsgException(CodeEnum.REQUEST_PARAM_NOT_FULL_ERROR);
        }

        //查询各项目id及版本类型下最新版本
        List<ReturnPlanVersion> returnPlanVersionList = dmInvestmentReturnMapper.selectNewestVersionGroupByProjectIdAndVersionType(projectId,yearMonth);
        if (CollectionUtils.isEmpty(returnPlanVersionList)) {
            return;
        }
        //转换map(key:回款计划版本id,value:回款计划版本)
        Map<String, ReturnPlanVersion> returnPlanVersionMap = returnPlanVersionList.stream().collect(Collectors.toMap(ReturnPlanVersion::getId, s -> s));
        //获取回款计划详情列表
        List<ReturnPlanVersionDetail> returnPlanVersionDetailList = returnPlanVersionDetailWrapper.selectByVersionIdList(new ArrayList<>(returnPlanVersionMap.keySet()), IsDeleteEnum.NO.getKey());
        //转换map(key:版本类型,value:(key:项目id,value:(key:标准业态编码,value:回款计划详情列表)))
        Map<String,Map<String, Map<String, List<ReturnPlanVersionDetail>>>> returnPlanVersionDetailByVersionTypeMap = returnPlanVersionDetailList.stream()
                .collect(Collectors.groupingBy(s -> returnPlanVersionMap.get(s.getVersionId()).getVersionType(),
                        Collectors.groupingBy(s -> returnPlanVersionMap.get(s.getVersionId()).getProjectId(),
                                Collectors.groupingBy(ReturnPlanVersionDetail::getProProductCode))));

        List<DmInvestmentReturn> dmInvestmentReturnList = new ArrayList<>();
        LocalDateTime now = LocalDateTime.now();
        int oneYear = now.getYear();
        int twoYear = now.plusYears(1).getYear();
        int threeYear = now.plusYears(2).getYear();
        int fourYear = now.plusYears(3).getYear();
        int fiveYear = now.plusYears(4).getYear();
        int sixYear = now.plusYears(5).getYear();
        for (Map.Entry<String, Map<String, Map<String, List<ReturnPlanVersionDetail>>>> versionTypeEntry : returnPlanVersionDetailByVersionTypeMap.entrySet()){
            for (Map.Entry<String, Map<String, List<ReturnPlanVersionDetail>>> projectIdEntry :  versionTypeEntry.getValue().entrySet()){
                for (Map.Entry<String, List<ReturnPlanVersionDetail>> proProductCodeEntry : projectIdEntry.getValue().entrySet()){
                    List<ReturnPlanVersionDetail> details = proProductCodeEntry.getValue();
                    ReturnPlanVersionDetail detail = details.get(0);

                    //以年月分组计算回款合计
                    Map<Integer, Map<Integer, BigDecimal>> totalReturnAmountMap = details.stream()
                            .collect(Collectors.groupingBy(s -> s.getReturnTime().getYear(),
                                    Collectors.toMap(s -> s.getReturnTime().getMonthValue(),
                                            ReturnPlanVersionDetail::getTotalReturnAmount,(s1, s2)-> s1 = s1.add(s2))));
                    //获取历史月回款合计
                    BigDecimal history = totalReturnAmountMap.entrySet().stream()
                            .filter(s -> s.getKey() < oneYear)
                            .flatMap(s -> s.getValue().entrySet().stream().map(Map.Entry::getValue))
                            .reduce(BigDecimal.ZERO, BigDecimal::add);
                    //获取历史月回款合计
                    BigDecimal future = totalReturnAmountMap.entrySet().stream()
                            .filter(s -> s.getKey() > sixYear)
                            .flatMap(s -> s.getValue().entrySet().stream().map(Map.Entry::getValue))
                            .reduce(BigDecimal.ZERO, BigDecimal::add);


                    DmInvestmentReturn dmInvestmentReturn = new DmInvestmentReturn();
                    dmInvestmentReturn.setAffiliationMonth(yearMonth);
                    dmInvestmentReturn.setRegionId(returnPlanVersionMap.get(detail.getVersionId()).getRegionId());
                    dmInvestmentReturn.setRegionName(returnPlanVersionMap.get(detail.getVersionId()).getRegionName());
                    dmInvestmentReturn.setCityCompanyId(returnPlanVersionMap.get(detail.getVersionId()).getCityCompanyId());
                    dmInvestmentReturn.setCityCompanyName(returnPlanVersionMap.get(detail.getVersionId()).getCityCompanyName());
                    dmInvestmentReturn.setProjectId(returnPlanVersionMap.get(detail.getVersionId()).getProjectId());
                    dmInvestmentReturn.setProjectCode(returnPlanVersionMap.get(detail.getVersionId()).getProjectCode());
                    dmInvestmentReturn.setProjectName(returnPlanVersionMap.get(detail.getVersionId()).getProjectName());
                    dmInvestmentReturn.setVersionType(versionTypeEntry.getKey());
                    dmInvestmentReturn.setProProductCode(detail.getProProductCode());
                    dmInvestmentReturn.setProProductType(detail.getProProductType());
                    dmInvestmentReturn.setHistory(history);
                    dmInvestmentReturn.setOneMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,oneYear,1));
                    dmInvestmentReturn.setTwoMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,oneYear,2));
                    dmInvestmentReturn.setThreeMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,oneYear,3));
                    dmInvestmentReturn.setFourMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,oneYear,4));
                    dmInvestmentReturn.setFiveMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,oneYear,5));
                    dmInvestmentReturn.setSixMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,oneYear,6));
                    dmInvestmentReturn.setSevenMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,oneYear,7));
                    dmInvestmentReturn.setEightMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,oneYear,8));
                    dmInvestmentReturn.setNineMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,oneYear,9));
                    dmInvestmentReturn.setTenMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,oneYear,10));
                    dmInvestmentReturn.setElevenMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,oneYear,11));
                    dmInvestmentReturn.setTwelveMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,oneYear,12));
                    dmInvestmentReturn.setThirteenMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,twoYear,1));
                    dmInvestmentReturn.setFourteenMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,twoYear,2));
                    dmInvestmentReturn.setFifteenMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,twoYear,3));
                    dmInvestmentReturn.setSixteenMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,twoYear,4));
                    dmInvestmentReturn.setSeventeenMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,twoYear,5));
                    dmInvestmentReturn.setEighteenMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,twoYear,6));
                    dmInvestmentReturn.setNineteenMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,twoYear,7));
                    dmInvestmentReturn.setTwentyMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,twoYear,8));
                    dmInvestmentReturn.setTwentyOneMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,twoYear,9));
                    dmInvestmentReturn.setTwentyTwoMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,twoYear,10));
                    dmInvestmentReturn.setTwentyThreeMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,twoYear,11));
                    dmInvestmentReturn.setTwentyFourMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,twoYear,12));
                    dmInvestmentReturn.setTwentyFiveMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,threeYear,1));
                    dmInvestmentReturn.setTwentySixMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,threeYear,2));
                    dmInvestmentReturn.setTwentySevenMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,threeYear,3));
                    dmInvestmentReturn.setTwentyEightMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,threeYear,4));
                    dmInvestmentReturn.setTwentyNineMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,threeYear,5));
                    dmInvestmentReturn.setThirtyMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,threeYear,6));
                    dmInvestmentReturn.setThirtyOneMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,threeYear,7));
                    dmInvestmentReturn.setThirtyTwoMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,threeYear,8));
                    dmInvestmentReturn.setThirtyThreeMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,threeYear,9));
                    dmInvestmentReturn.setThirtyFourMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,threeYear,10));
                    dmInvestmentReturn.setThirtyFiveMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,threeYear,11));
                    dmInvestmentReturn.setThirtySixMonth(this.getTotalReturnAmountByMap(totalReturnAmountMap,threeYear,12));
                    dmInvestmentReturn.setFourYearOneQuarter(this.getTotalReturnAmountByMap(totalReturnAmountMap,fourYear,1,3));
                    dmInvestmentReturn.setFourYearTwoQuarter(this.getTotalReturnAmountByMap(totalReturnAmountMap,fourYear,4,6));
                    dmInvestmentReturn.setFourYearThreeQuarter(this.getTotalReturnAmountByMap(totalReturnAmountMap,fourYear,7,9));
                    dmInvestmentReturn.setFourYearFourQuarter(this.getTotalReturnAmountByMap(totalReturnAmountMap,fourYear,10,12));
                    dmInvestmentReturn.setFiveYearOneQuarter(this.getTotalReturnAmountByMap(totalReturnAmountMap,fiveYear,1,3));
                    dmInvestmentReturn.setFiveYearTwoQuarter(this.getTotalReturnAmountByMap(totalReturnAmountMap,fiveYear,4,6));
                    dmInvestmentReturn.setFiveYearThreeQuarter(this.getTotalReturnAmountByMap(totalReturnAmountMap,fiveYear,7,9));
                    dmInvestmentReturn.setFiveYearFourQuarter(this.getTotalReturnAmountByMap(totalReturnAmountMap,fiveYear,10,12));
                    dmInvestmentReturn.setSixYearOneQuarter(this.getTotalReturnAmountByMap(totalReturnAmountMap,sixYear,1,3));
                    dmInvestmentReturn.setSixYearTwoQuarter(this.getTotalReturnAmountByMap(totalReturnAmountMap,sixYear,4,6));
                    dmInvestmentReturn.setSixYearThreeQuarter(this.getTotalReturnAmountByMap(totalReturnAmountMap,sixYear,7,9));
                    dmInvestmentReturn.setSixYearFourQuarter(this.getTotalReturnAmountByMap(totalReturnAmountMap,sixYear,10,12));
                    dmInvestmentReturn.setFuture(future);
                    dmInvestmentReturnList.add(dmInvestmentReturn);
                }
            }
        }
        //删除项目回款系数分析表数据
        delByYearMonthAndProjectId(yearMonth, projectId);
        //写入项目回款系数分析表数据
        dmInvestmentReturnMapper.insertList(dmInvestmentReturnList);
    }

    /**
     * 获取指定年月的回款合计
     * @param totalReturnAmountMap 回款合计Map
     * @param year 年
     * @param month 月
     * @return
     */
    private BigDecimal getTotalReturnAmountByMap(Map<Integer, Map<Integer, BigDecimal>> totalReturnAmountMap, int year, int month) {
        if(CollectionUtils.isNotEmpty(totalReturnAmountMap.get(year)) && null != totalReturnAmountMap.get(year).get(month)){
            return totalReturnAmountMap.get(year).get(month);
        }
        return BigDecimal.ZERO;
    }

    /**
     * 获取指定年,大于等于最小月,小于等于最大月的回款合计
     * @param totalReturnAmountMap 回款合计Map
     * @param year 年
     * @param minMonth 最小月
     * @param maxMonth 最大月
     * @return
     */
    private BigDecimal getTotalReturnAmountByMap(Map<Integer, Map<Integer, BigDecimal>> totalReturnAmountMap, int year, int minMonth,int maxMonth) {
        return totalReturnAmountMap.entrySet().stream()
                .filter(s -> s.getKey() == year)
                .flatMap(s -> s.getValue().entrySet().stream().filter(s1 -> s1.getKey() >= minMonth &&  s1.getKey() <= maxMonth).map(Map.Entry::getValue))
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    /**
     * 删除项目回款系数分析表数据
     * @param yearMonth 年月
     * @param projectId 项目id
     */
    private void delByYearMonthAndProjectId(String yearMonth, String projectId) {
        QueryWrapper<DmInvestmentReturn> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("affiliation_month", yearMonth).eq(StringUtils.isNotEmpty(projectId), "project_id", projectId);
        dmInvestmentReturnMapper.delete(queryWrapper);
    }

    /**
     * 查询投资回款分析表数据
     *
     * @param projectIdList 项目id列表
     * @param yearMonth     年月
     * @param versionType   版本类型
     * @param vsVersionType VS版本类型
     * @return
     */
    @Override
    public List<InvestmentReturnReportVo> dmInvestmentReturn(List<String> projectIdList, String yearMonth, String versionType, String vsVersionType) {
        if (StringUtils.isEmpty(yearMonth) || StringUtils.isEmpty(versionType) || StringUtils.isEmpty(vsVersionType)) {
            throw new MsgException(CodeEnum.REQUEST_PARAM_NOT_FULL_ERROR);
        }
        //查询投资回款列表
        List<DmInvestmentReturn> dmInvestmentReturnList = dmInvestmentReturnMapper.selectByAffiliationMonthAndVersionType(projectIdList,yearMonth, Arrays.asList(versionType, vsVersionType));
        if (CollectionUtils.isEmpty(dmInvestmentReturnList)) {
            return new ArrayList<>();
        }
        //转换Map(key:版本类型,value:(key:项目id,value:(key:标准业态编码,value:回款系数详情列表)))
        Map<String, Map<String, Map<String, DmInvestmentReturn>>> dmInvestmentReturnByVersionTypeMap = dmInvestmentReturnList.stream()
                .collect(Collectors.groupingBy(DmInvestmentReturn::getVersionType,
                        Collectors.groupingBy(DmInvestmentReturn::getProjectId, Collectors.toMap(DmInvestmentReturn::getProProductCode, s -> s))));

        //转换Map(key:项目id,value:标准业态编码列表)
        Map<String, List<String>> proProductCodeListMap = dmInvestmentReturnList.stream()
                .filter(s -> versionType.equals(s.getVersionType()))
                .collect(Collectors.groupingBy(DmInvestmentReturn::getProjectId, Collectors.mapping(DmInvestmentReturn::getProProductCode, Collectors.toList())));

        List<InvestmentReturnReportVo> voList = new ArrayList<>();
        for (Map.Entry<String, List<String>> proProductCodeListEntry : proProductCodeListMap.entrySet()) {
            //项目id
            String projectId = proProductCodeListEntry.getKey();
            for (String proProductCode : proProductCodeListEntry.getValue()) {
                if (CollectionUtils.isEmpty(dmInvestmentReturnByVersionTypeMap.get(versionType))) {
                    continue;
                }
                //当前回款计划
                DmInvestmentReturn dmReturn = dmInvestmentReturnByVersionTypeMap.get(versionType).get(projectId).get(proProductCode);
                //对比回款计划
                DmInvestmentReturn vsDmReturn = null;
                if (CollectionUtils.isNotEmpty(dmInvestmentReturnByVersionTypeMap.get(vsVersionType))
                        && CollectionUtils.isNotEmpty(dmInvestmentReturnByVersionTypeMap.get(vsVersionType).get(projectId))
                        && null != dmInvestmentReturnByVersionTypeMap.get(vsVersionType).get(projectId).get(proProductCode)) {
                    vsDmReturn = dmInvestmentReturnByVersionTypeMap.get(vsVersionType).get(projectId).get(proProductCode);
                }
                Map<Integer, Object> monthMap = dmReturn.getMonthMap();
                Map<Integer, Object> quarterMap = dmReturn.getQuarterMap();
                Map<Integer, Object> vsMonthMap = vsDmReturn == null ? MyMapUtils.getMoneyMap(36) : vsDmReturn.getMonthMap();
                Map<Integer, Object> vsQuarterMap = vsDmReturn == null ? MyMapUtils.getMoneyMap(12) : vsDmReturn.getQuarterMap();

                //历史月回款合计对比
                VsReturnReportVo history = new VsReturnReportVo();
                history.setCompare(dmReturn.getHistory());
                history.setBeCompared(vsDmReturn == null ? "-" : vsDmReturn.getHistory());
                history.setDifference(vsDmReturn == null ? "-" : dmReturn.getHistory().subtract(vsDmReturn.getHistory()));
                //月度回款合计对比列表
                List<VsReturnReportVo> vsMonthList = new ArrayList<>();
                for (Map.Entry<Integer, Object> monthEntry : monthMap.entrySet()) {
                    VsReturnReportVo vo = new VsReturnReportVo();

                    Integer num = monthEntry.getKey();
                    Object money = monthEntry.getValue();
                    Object vsMoney = vsMonthMap.get(num);
                    Object difference;
                    if (!"-".equals(money) && !"-".equals(vsMoney)) {
                        difference = ((BigDecimal) money).subtract((BigDecimal) vsMoney);
                    } else {
                        difference = "-";
                    }
                    vo.setCompare(money);
                    vo.setBeCompared(vsMoney);
                    vo.setDifference(difference);
                    vsMonthList.add(vo);
                }
                //季度回款合计对比列表
                List<VsReturnReportVo> vsQuarterList = new ArrayList<>();
                for (Map.Entry<Integer, Object> monthEntry : quarterMap.entrySet()) {
                    Integer num = monthEntry.getKey();
                    Object money = monthEntry.getValue();
                    Object vsMoney = vsQuarterMap.get(num);
                    Object difference;
                    if (!"-".equals(money) && !"-".equals(vsMoney)) {
                        difference = ((BigDecimal) money).subtract((BigDecimal) vsMoney);
                    } else {
                        difference = "-";
                    }

                    VsReturnReportVo vo = new VsReturnReportVo();
                    vo.setCompare(money);
                    vo.setBeCompared(vsMoney);
                    vo.setDifference(difference);
                    vsQuarterList.add(vo);
                }
                //历史月回款合计对比
                VsReturnReportVo future = new VsReturnReportVo();
                future.setCompare(dmReturn.getFuture());
                future.setBeCompared(vsDmReturn == null ? "-" : vsDmReturn.getFuture());
                future.setDifference(vsDmReturn == null ? "-" : dmReturn.getFuture().subtract(vsDmReturn.getFuture()));

                InvestmentReturnReportVo vo = new InvestmentReturnReportVo();
                vo.setRegionName(dmReturn.getRegionName());
                vo.setCityCompanyName(dmReturn.getCityCompanyName());
                vo.setProjectCode(dmReturn.getProjectCode());
                vo.setProjectName(dmReturn.getProjectName());
                vo.setProProductCode(dmReturn.getProProductCode());
                vo.setProProductType(dmReturn.getProProductType());
                vo.setHistory(history);
                vo.setVsMonthList(vsMonthList);
                vo.setVsQuarterList(vsQuarterList);
                vo.setFuture(future);
                voList.add(vo);
            }
        }
        return voList;
    }

    /**
     * 刷新能力版回款计划
     * @param projectId
     * @param yearMonth
     */
    @Transactional
    @Override
    public void refreshAbilityReturnPlan(String projectId, String yearMonth) {
        if (StringUtils.isEmpty(yearMonth)) {
            throw new MsgException(CodeEnum.REQUEST_PARAM_NOT_FULL_ERROR);
        }
        IdmUser user = new IdmUser();
        user.setAlias(Constants.SYS);

        delAbilityReturnPlanVersion(yearMonth);

        //查询指定年月最新动态版签约计划版本列表
        List<SignPlanVersion> signPlanVersionList = signPlanVersionMapper.selectLatestVersionByAffiliationMonthAndVersionTypeAndVersionState(yearMonth,projectId,VersionTypeEunm.DYNAMIC.getKey(),VersionStatusEnum.SUCCESSAPPROVED.getKey(),IsDeleteEnum.NO.getKey());
        for(SignPlanVersion signPlanVersion : signPlanVersionList){
            //手动开启事务
            DataSourceTransactionManager dSTransactionManager = new DataSourceTransactionManager();
            dSTransactionManager.setDataSource(dataSource);
            DefaultTransactionDefinition dtDefinition = new DefaultTransactionDefinition();
            //新发起一个事务
            dtDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
            //获取事务状态
            TransactionStatus transactionStatus = dSTransactionManager.getTransaction(dtDefinition);

            try {
                //创建能力版回款计划版本
                ReturnPlanVersion returnPlanVersion = this.createAbilityReturnPlanVersion(signPlanVersion,user);
                //创建回款计划版本系数列表
                returnPlanVersionCoefficientService.createByInvestmentList(returnPlanVersion, user);
                //创建回款计划详情列表
                returnPlanVersionDetailService.createList(returnPlanVersion);

                //逻辑代码，可以写上你的逻辑处理代码
                dSTransactionManager.commit(transactionStatus);
            }catch (MsgException e){
                dSTransactionManager.rollback(transactionStatus);
                SysLogUtils.addSysLog(LogEventEnum.REFRESH,"投资回款分析表","刷新能力版回款计划","项目id:"+signPlanVersion.getProjectId()+",分期id:"+signPlanVersion.getProjectfId()+".错误原因："+e.getMsg());
            }catch (Exception e){
                dSTransactionManager.rollback(transactionStatus);
                SysLogUtils.addSysLog(LogEventEnum.REFRESH,"投资回款分析表","刷新能力版回款计划","项目id:"+signPlanVersion.getProjectId()+",分期id:"+signPlanVersion.getProjectfId()+".错误原因："+e.getLocalizedMessage());
            }
        }
    }

    /**
     * 删除能力版回款计划版本
     * @param yearMonth
     */
    private void delAbilityReturnPlanVersion(String yearMonth) {
        List<ReturnPlanVersion> returnPlanVersionList = returnPlanVersionWrapper.selectByYearMonth(VersionTypeEunm.ABILITY.getKey(), yearMonth, IsDeleteEnum.NO.getKey());
        if(CollectionUtils.isNotEmpty(returnPlanVersionList)){
            List<String> versionIdList = returnPlanVersionList.stream().map(s -> s.getId()).collect(Collectors.toList());

            //删除版本数据
            QueryWrapper<ReturnPlanVersion> queryWrapper1 = new QueryWrapper<>();
            queryWrapper1.in("id",versionIdList);
            returnPlanVersionMapper.delete(queryWrapper1);
            //删除版本系数详情数据
            QueryWrapper<ReturnPlanVersionCoefficient> queryWrapper2 = new QueryWrapper<>();
            queryWrapper2.in("return_plan_version_id",versionIdList);
            returnPlanVersionCoefficientMapper.delete(queryWrapper2);
            //删除版本详情数据
            QueryWrapper<ReturnPlanVersionDetail> queryWrapper3 = new QueryWrapper<>();
            queryWrapper3.in("version_id",versionIdList);
            returnPlanVersionDetailMapper.delete(queryWrapper3);
        }
    }

    /**
     * 创建回款计划版本
     * @param signPlanVersion 签约计划版本
     * @param user
     */
    private ReturnPlanVersion createAbilityReturnPlanVersion(SignPlanVersion signPlanVersion, IdmUser user) {
        ReturnPlanVersion returnPlanVersion = new ReturnPlanVersion();

        String id = UUIDUtils.create();
        //分期id
        String stageId = signPlanVersion.getProjectfId();
        //版本号
        String versionNum = returnPlanVersionService.getVersionNum(stageId, VersionTypeEunm.ABILITY.getKey(),null,signPlanVersion.getAffiliationMonth());
        //分期取数系统
        SysProjectFetchNumber sysProjectFetchNumber = sysProjectFetchNumberService.selectByFid(stageId);
        //是否进入一房一价
        int isContainSale = 0;
        List<MymRooms> rooms = mymRoomsService.selectNewestWarPlanByFid(stageId);
        if(CollectionUtils.isNotEmpty(rooms)){
            isContainSale =  1;
        }

        returnPlanVersion.setId(id);
        returnPlanVersion.setVersionType(VersionTypeEunm.ABILITY.getKey());
        returnPlanVersion.setVersionNum(versionNum);
        returnPlanVersion.setProjectId(signPlanVersion.getProjectId());
        returnPlanVersion.setStageId(stageId);
        returnPlanVersion.setVersionState(VersionStatusEnum.SYSGENERATION.getKey());
        returnPlanVersion.setSignPlanVersionId(signPlanVersion.getId());
        returnPlanVersion.setSupplyPlanVersionId(signPlanVersion.getSourceSupplyId());
        returnPlanVersion.setResourceMatching(null);
        returnPlanVersion.setAnnualObjectives(null);
        returnPlanVersion.setCompileYear(null);
        returnPlanVersion.setVersionIdentify(null);
        returnPlanVersion.setSourceVersionId(null);
        returnPlanVersion.setIsAssessment(WhetherEnum.NO.getKey());
        returnPlanVersion.setAffiliationMonth(signPlanVersion.getAffiliationMonth());
        returnPlanVersion.setDataSource(sysProjectFetchNumber.getCountingSystemId());
        returnPlanVersion.setIsFinalization(WhetherEnum.NO.getKey());
        returnPlanVersion.setCreateBy(user.getAlias());
        returnPlanVersion.setCreateTime(LocalDateTime.now());
        returnPlanVersion.setVersionCreate(VersionCreateEnum.AUTOMATICCREATE.getKey());
        returnPlanVersion.setUpdateBy(user.getAlias());
        returnPlanVersion.setUpdateTime(LocalDateTime.now());
        returnPlanVersion.setIsDelete(IsDeleteEnum.NO.getKey());
        returnPlanVersion.setDescription(null);
        returnPlanVersion.setIsStageNewest(WhetherEnum.NO.getKey());
        returnPlanVersion.setIsContainSale(isContainSale);
        returnPlanVersionMapper.insert(returnPlanVersion);
        return returnPlanVersion;
    }
}
